using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using UMC.Net;
using UMC.Web;

namespace UMC.ITME
{
    class HttpLogerDoWorker : UMC.Host.IDoWorker
    {
        public HttpLogerDoWorker()
        {
            ReloadAlert();

        }
        class AlertInfo
        {
            public int Type;
            public string Caption;
            public uint Key;
            public ItemAlert[] items;

        }
        class ItemAlert
        {
            public HttpLogerType Type;
            public StringValue Value;
        }
        class AlertPost
        {
            public AlertInfo Key { get; set; }
            public bool Post { get; set; }
        }
        public static void AppendLog(NetLoger netLoger)
        {
            netLogers.Enqueue(netLoger);
        }
        public static void ReloadAlert()
        {

            var alertInfos = new System.Collections.Generic.List<AlertInfo>();
            var alerts = DataFactory.Instance().Alert();
            foreach (var alert in alerts)
            {
                if (alert.Id.HasValue == false || alert.Type.HasValue == false)
                {
                    continue;
                }
                var alertInfo = new AlertInfo();
                alertInfo.Caption = alert.Title?.UTF8();
                alertInfo.Key = alert.Id.Value;
                alertInfo.Type = (int)Math.Pow(2, (int)alert.Type.Value);
                var ItemAlerts = new System.Collections.Generic.List<ItemAlert>();
                switch (alert.Type.Value)
                {
                    case HttpLogerType.Error:
                    case HttpLogerType.Alert:
                    case HttpLogerType.Info:
                    case HttpLogerType.Debug:

                        break;
                    case HttpLogerType.Status:
                        if (alert.Value?.Length > 0)
                        {
                            var values = alert.Value.UTF8().Split('|', StringSplitOptions.RemoveEmptyEntries);
                            var bytes = new byte[values.Length * 4];
                            for (var i = 0; i < values.Length; i++)
                            {
                                BitConverter.TryWriteBytes(bytes.AsSpan(i * 4), Utility.IntParse(values[i], 0));
                            }

                            ItemAlerts.Add(new ItemAlert { Type = alert.Type.Value, Value = new StringValue(bytes) });
                        }
                        break;
                    case HttpLogerType.Duration:
                        if (alert.Value?.Length > 0)
                        {
                            ItemAlerts.Add(new ItemAlert { Type = alert.Type.Value, Value = new StringValue(BitConverter.GetBytes(Utility.IntParse(alert.Value.UTF8(), 0))) });
                        }
                        break;
                    default:
                        if (alert.Value?.Length > 0)
                        {
                            ItemAlerts.Add(new ItemAlert { Type = alert.Type.Value, Value = alert.Value });
                        }
                        break;
                }

                var content = alert.Content ?? StringValue.Empty;//.UTF8();
                var span = content.Span;

                while (span.Length > 1)
                {
                    var atype = (HttpLogerType)span[0];
                    var l = span[1];
                    alertInfo.Type |= (int)Math.Pow(2, (int)atype);
                    if (l > 0)
                    {
                        var itemvalue = span.Slice(2, l);
                        switch (atype)
                        {
                            case HttpLogerType.Status:
                                {
                                    var values = itemvalue.UTF8().Split('|', StringSplitOptions.RemoveEmptyEntries);
                                    var bytes = new byte[values.Length * 4];
                                    for (var i = 0; i < values.Length; i++)
                                    {
                                        BitConverter.TryWriteBytes(bytes.AsSpan(i * 4), Utility.IntParse(values[i], 0));
                                    }

                                    ItemAlerts.Add(new ItemAlert { Type = alert.Type.Value, Value = new StringValue(bytes) });
                                }
                                break;
                            case HttpLogerType.Duration:
                                ItemAlerts.Add(new ItemAlert { Type = alert.Type.Value, Value = new StringValue(BitConverter.GetBytes(Utility.IntParse(itemvalue.UTF8(), 0))) });

                                break;
                            default:

                                ItemAlerts.Add(new ItemAlert { Type = atype, Value = new StringValue(itemvalue.ToArray()) });
                                break;
                        }
                    }
                    span = span.Slice(l + 2);
                }
                alertInfo.items = ItemAlerts.ToArray();

                alertInfos.Add(alertInfo);
            }
            AlertInfos = alertInfos.ToArray();
        }
        static AlertInfo[] AlertInfos = new AlertInfo[0];
        static ConcurrentQueue<NetLoger> netLogers = new ConcurrentQueue<NetLoger>();
        public void DoWork()
        {
            var date = DateTime.Now;
            var filename = UMC.Data.Utility.MapPath(String.Format("Logs\\{0:yy-MM-dd}.log", date));
            if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(filename)))
            {
                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename));
            }
            try
            {
                var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                using (var file = File.Open(filename, FileMode.Append, FileAccess.Write, FileShare.Read))
                {
                    while (netLogers.TryDequeue(out var logbuffer))
                    {
                        var chunk = logbuffer.Chunk;
                        chunk.Temp();
                        var atis = AlertInfos.Where(r => (r.Type & logbuffer.SizeType) != 0).Select(r => new AlertPost { Key = r, Post = true }).ToArray();
                        if (atis.Length > 0)
                        {
                            var appName = string.Empty;
                            {
                                var span = chunk.Chunk.AsSpan(10, chunk.Size - 10); ;
                                while (span.Length > 1)
                                {
                                    HttpLogerType logType = (HttpLogerType)(byte)(span[0] >> 4);
                                    var size = ((span[0] & 0x0f) << 8) | span[1];
                                    var value = span.Slice(2, size);
                                    if (logType == HttpLogerType.Host)
                                    {
                                        appName = value.UTF8();
                                    }
                                    foreach (var v in atis)
                                    {
                                        if (v.Key.items.Length > 0 && v.Post)
                                        {
                                            foreach (var item in v.Key.items)
                                            {
                                                if (item.Type == logType)
                                                {
                                                    switch (item.Type)
                                                    {
                                                        case HttpLogerType.Path:
                                                            v.Post = value.StartsWith(item.Value.Span);
                                                            break;
                                                        default:
                                                        case HttpLogerType.Host:
                                                        case HttpLogerType.Username:
                                                        case HttpLogerType.Status:
                                                            v.Post = item.Value.Span.Contains(value);
                                                            break;
                                                        case HttpLogerType.Duration:
                                                            v.Post = value.Int32() > item.Value.Int32();
                                                            break;
                                                    }
                                                    if (v.Post == false)
                                                    {
                                                        break;
                                                    }
                                                }

                                            }
                                        }

                                    }


                                    span = span.Slice(2 + size);
                                }
                            }
                            foreach (var alertPost in atis)
                            {
                                if (alertPost.Post)
                                {
                                    var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();
                                    UMC.ITME.Utility.Sign(webr, secret);

                                    webr.Put(new WebMeta().Put("type", "Alert").Put("key", alertPost.Key.Key).Put("caption", alertPost.Key.Caption).Put("appName", String.IsNullOrEmpty(appName) ? "IT管理引擎" : appName).Put("position", $"{date:yy-MM-dd}-{file.Position}"), xhr =>
                                    {

                                    });
                                }
                            }
                        }

                        var b = new byte[6];
                        b[0] = 0x02;
                        b[1] = 0x02;
                        BitConverter.TryWriteBytes(b.AsSpan(2), chunk.Size);
                        file.Write(b);
                        BitConverter.TryWriteBytes(chunk.Chunk.AsSpan(6), logbuffer.SizeType);

                        file.Write(chunk.Chunk, 0, chunk.Size);

                        BitConverter.TryWriteBytes(b, chunk.Size);
                        b[4] = 0x03;
                        b[5] = 0x03;
                        file.Write(b);
                        chunk.Dispose();
                        file.Flush();
                    }

                    file.Close();
                }
            }
            catch //(Exception ex)
            {

            }

            HttpMimeServier.Register(10, this);
        }
    }

}